#include <cstdio>
#include <fstream>
#include <string>
#include <sstream>

#include"mesh.h"


namespace 
{
    inline void emptyStr(std::string& str)
    {
        for (auto& Iter : str)
        {
            if (Iter == ',') Iter = ' ';
        }
    }

    inline void getLine(std::ifstream& file, std::string& str)
    {
        while (!file.eof())
        {
            std::getline(file, str);
            if (str.empty()) continue;
            if (str.size() >= 2 && (str[0] == '*' && str[1] == '*')) continue;//注释
            for (int i = 0; i < str.size(); i++)
            {
                if (str[i] >= 'a' && str[i] <= 'z')
                {                         // 判断是否在小写字母范围内
                    str[i] = str[i] - 32; // 转换大小写
                }
            }
            break;
        }
        return;
    }
} // namespace

void INPMesh::readFormFile(const char* filename)
{
    std::ifstream file(filename);
    std::string   tempStr;
    bool          flag = true;

    ConnSize = 0; // 单元的尺寸相关的信息

    // 目前只考虑part的类型

    readNodeAndElements(file, tempStr);

    file.close();

    PConnSize = 0;
    faceListNodeSize = 0;
    // 生成face相关的信息
    for (auto ElemIndex = 0; ElemIndex != ElemList_.size(); ++ElemIndex)
    {

        std::vector<INPFace> elemFaces;
        auto& elem = ElemList_[ElemIndex];
       // if (elem.elemtype_ == HEXAHEDRON || elem.elemtype_ == VOXEL)
        if (elem.elemtype_ == HEXAHEDRON)
        {
            PConnSize += 1 + 6 * 5;
            elemFaces.resize(6);
            // 6个面
            elemFaces[0].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[3]);

            elemFaces[1].NodeIds.insert(elem.nodeIds[4]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[5]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[6]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[7]);

            elemFaces[2].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[3]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[4]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[7]);

            elemFaces[3].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[5]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[6]);

            elemFaces[4].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[4].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[4].NodeIds.insert(elem.nodeIds[4]);
            elemFaces[4].NodeIds.insert(elem.nodeIds[5]);

            elemFaces[5].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[5].NodeIds.insert(elem.nodeIds[3]);
            elemFaces[5].NodeIds.insert(elem.nodeIds[6]);
            elemFaces[5].NodeIds.insert(elem.nodeIds[7]);


        }
        else if (elem.elemtype_ == TETRA)
        {
            PConnSize += 1 + 4 * 4;
            elemFaces.resize(4);
            elemFaces[0].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[2]);

            elemFaces[1].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[3]);

            elemFaces[2].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[3]);

            elemFaces[3].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[3]);
        }
        // 金字塔单元
        else if (elem.elemtype_ == PYRAMID)
        {
            elemFaces.resize(5);
            elemFaces[0].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[3]);

            elemFaces[1].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[3]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[4]);

            elemFaces[2].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[4]);

            elemFaces[3].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[4]);

            elemFaces[4].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[4].NodeIds.insert(elem.nodeIds[3]);
            elemFaces[4].NodeIds.insert(elem.nodeIds[4]);
        }
        else if (elem.elemtype_ == WEDGE)
        {
            elemFaces.clear();
            elemFaces.resize(5);
            elemFaces[0].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[0].NodeIds.insert(elem.nodeIds[2]);

            elemFaces[1].NodeIds.insert(elem.nodeIds[3]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[4]);
            elemFaces[1].NodeIds.insert(elem.nodeIds[5]);

            elemFaces[2].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[3]);
            elemFaces[2].NodeIds.insert(elem.nodeIds[4]);

            elemFaces[3].NodeIds.insert(elem.nodeIds[1]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[4]);
            elemFaces[3].NodeIds.insert(elem.nodeIds[5]);

            elemFaces[4].NodeIds.insert(elem.nodeIds[0]);
            elemFaces[4].NodeIds.insert(elem.nodeIds[2]);
            elemFaces[4].NodeIds.insert(elem.nodeIds[3]);
            elemFaces[4].NodeIds.insert(elem.nodeIds[5]);
        }
        else
        {
            printf("暂时不支持当前单元\n");
            exit(1);
        }

        // 判断面是否会重复
        for (int faceIndex = 0; faceIndex != elemFaces.size(); ++faceIndex)
        {
            auto& faceIter = elemFaces[faceIndex];
            auto  faceNodeId = *faceIter.NodeIds.begin();
            auto& NodeFaces = VertexsList_[faceNodeId].NodeFaceList;
            bool  found = false;
            for (auto NodeFaceIter : NodeFaces)
            {
                if (NodeFaceIter->NodeIds == faceIter.NodeIds)
                {
                    found = true;
                    NodeFaceIter->FaceOwerElemID.push_back(ElemIndex);
                    elem.faceIds.push_back(NodeFaceIter->id);
                    break;
                }
            }

            if (!found)
            {
                INPFace tempFace;
                tempFace.id = faceList_.size();
                tempFace.NodeIds = std::move(faceIter.NodeIds);
                tempFace.FaceOwerElemID.push_back(ElemIndex);
                faceListNodeSize += tempFace.NodeIds.size();
                faceList_.emplace_back(std::move(tempFace));

                auto& faceBack = faceList_.back();
                for (auto faceNodeIter : faceBack.NodeIds)
                {
                    VertexsList_[faceNodeIter].NodeFaceList.emplace_back(&faceList_.back());
                }
                elem.faceIds.emplace_back(faceBack.id);
            }
        }
    }

    // 生成对应的数据
    VertexSize = VertexsList_.size();
    ElemSize = ElemList_.size();
    faceSize = faceList_.size();
    NodeAdjSize = 0;
    for (auto& NodeIter : VertexsList_)
    {
        NodeAdjSize += NodeIter.adj.size();
    }
    ElemFaceIdSize = 0;
    for (auto& ElemIter : ElemList_) {
        ElemFaceIdSize += ElemIter.faceIds.size();
    }
}
//读取功能

void INPMesh::readNodeAndElements(std::ifstream& file, std::string& tempStr)
{
    std::stringstream ss;

    bool flag = true;

    while (!file.eof())
    {
        if (flag) 
        {
            getLine(file, tempStr);
        }
        else {
            flag = true;
        }

        if (tempStr.substr(0, 5) == "*NODE")
        {
            while (!file.eof())
            {
                ss.clear();
                ss.str("");
                getLine(file, tempStr);

                if (tempStr[0] == '*')
                {
                    flag = false;
                    break;
                }
                emptyStr(tempStr);
                ss << tempStr;
                INPNode tempNode;
                ss >> tempNode.id >> tempNode.coors[0] >> tempNode.coors[1] >> tempNode.coors[2];
                NodeOutIdTOInnerId_[tempNode.id] = VertexsList_.size();
                VertexsList_.emplace_back(tempNode);
            }
        }

       int TempType_;
        int         elemNodeSize = 0;
        if (tempStr.substr(0, 8) == "*ELEMENT") 
        {
            if (tempStr.substr(tempStr.find("TYPE=") + 5, 5) == "C3D8R")
            {
                TempType_ = HEXAHEDRON;
                elemNodeSize = 8;
            }
            else if (tempStr.substr(tempStr.find("TYPE=") + 5, 4) == "C3D8")
            {
                 TempType_ = HEXAHEDRON;
                elemNodeSize = 8;
            }
            else if (tempStr.substr(tempStr.find("TYPE=") + 5, 4) == "C3D4")
            {
                TempType_ = TETRA;
                elemNodeSize = 4;
            }
            else if (tempStr.substr(tempStr.find("TYPE=") + 5, 4) == "C3D5")
            {
               TempType_ = PYRAMID;
                elemNodeSize = 5;
            }

            else if (tempStr.substr(tempStr.find("TYPE=") + 5, 4) == "C3D6")
            {
               TempType_ = WEDGE;
                elemNodeSize = 6;
            }
            else
            {
                printf("暂时不支持当前的单元类型读入!\n");
                exit(1);
            }
            //对于某一单元类型进行迭代
            while (!file.eof())
            {
                INPElem tempElem;
               tempElem.elemtype_ = TempType_;
                ss.clear();
                ss.str("");
                getLine(file, tempStr);
                if (tempStr.empty() || tempStr[0] == '*')
                {
                    flag = false;
                    break;
                };
                emptyStr(tempStr);
                ss << tempStr;
                ss >> tempElem.id;
                int elemNodeId;
                int elemInnerId = ElemList_.size();
                int tempElemNodeSize = 0;
                while (tempElemNodeSize < elemNodeSize)
                {
                    while (ss >> elemNodeId)
                    {
                        auto InnerId = NodeOutIdTOInnerId_.at(elemNodeId);
                        VertexsList_[InnerId].adj.insert(elemInnerId); // 使用内部的id编号
                        tempElem.nodeIds.emplace_back(InnerId);
                        tempElemNodeSize++;
                    }
                    if (tempElemNodeSize < elemNodeSize)
                    {
                        getLine(file, tempStr);
                        emptyStr(tempStr);
                        ss.clear();
                        ss.str("");
                        ss << tempStr;
                    }
                }



                ElemList_.emplace_back(std::move(tempElem));
                ConnSize += elemNodeSize;
            }
        }
    }
}
